package com.project.MessageRoute.model;

import com.alibaba.fastjson.JSONObject;
import com.project.MessageRoute.annotation.MessageRouteMethod;
import com.project.MessageRoute.executor.MessageRouteSetting;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Mono;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.concurrent.CompletableFuture;

public class MessageRouteBean {
    private String name;
    private Method method;
    private Object bean;
    private String className;
    private boolean async;
    private String result;
    private MessageRouteMethod messageRouteMethod;

    public MessageRouteMethod getRouteMethod() {
        return messageRouteMethod;
    }

    public void setRouteMethod(MessageRouteMethod messageRouteMethod) {
        this.messageRouteMethod = messageRouteMethod;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public boolean isAsync() {
        return async;
    }

    public void setAsync(boolean async) {
        this.async = async;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    private Object[] parameters(String args, String cls){
        Method method = getMethod();
        Type[] parameterTypes = method.getGenericParameterTypes();
        Object[] inputs;
        if (StringUtils.isBlank(cls)){
            MessageValueEntity messageValueEntity = JSONObject.parseObject(args, MessageValueEntity.class);
            inputs = new Object[messageValueEntity.getParameter().length];
            for (int i=0;i<parameterTypes.length;i++){
                inputs[i] = null;
                try
                {
                    inputs[i] = JSONObject.parseObject(messageValueEntity.getParameter()[i], parameterTypes[i]);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            inputs = new Object[1];
            Class<?> type = MessageRouteSetting.getBeanType(cls);
            inputs[0] = null;
            try{
                inputs[0] = JSONObject.parseObject(args, type);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return inputs;
    }

    public String invoke(String args, String cls) throws InvocationTargetException, IllegalAccessException {
        Object obj = getMethod().invoke(getBean(), parameters(args, cls));
        return JSONObject.toJSONString(obj);
    }

    public String invoke(String args) throws InvocationTargetException, IllegalAccessException {
        return invoke(args, getClassName());
    }

    public Mono<String> syncInvoke(String args){
        return syncInvoke(args, getClassName());
    }

    public Mono<String> syncInvoke(String args, String cls){
        return Mono.fromFuture(CompletableFuture.supplyAsync (()->{
            try
            {
                Object obj = getMethod().invoke(getBean(), parameters(args, cls));
                return JSONObject.toJSONString(obj);
            } catch (Exception e){
                throw new RuntimeException(e);
            }
        }));
    }

}
